package com.cpit.platform.service.impl;

import com.cpit.platform.common.dao.Criteria;
import com.cpit.platform.common.dao.Criterion;
import com.cpit.platform.common.dao.Restrictions;
import com.cpit.platform.common.dao.SimpleExpression;
import com.cpit.platform.common.entity.Result;
import com.cpit.platform.common.entity.TableDataQueryCondition;
import com.cpit.platform.common.entity.TableJsonData;
import com.cpit.platform.common.excel.ExportExcel;
import com.cpit.platform.common.excel.annotation.ExcelField;
import com.cpit.platform.common.utils.DateUtil;
import com.cpit.platform.common.utils.Reflections;
import com.cpit.platform.dao.EntityRepository;
import com.cpit.platform.dto.BaseEntity;
import com.cpit.platform.log.LogOperator;
import com.cpit.platform.service.EntityService;
import org.apache.catalina.servlet4preview.http.HttpServletRequest;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

public abstract class EntityServiceImpl<GenericClass> implements EntityService<GenericClass> {
    private final String loggerName = this.getClass().getName();
    protected abstract EntityRepository getEntityRepository();

    @Override
    public Result<GenericClass>  create(GenericClass data){
        LogOperator.debug(loggerName, "create data = "+data);
        Result<GenericClass> result;
        try {
            String msg = beforeCreate(data);
            if((!StringUtils.isEmpty(msg))){
                return transColumnName(new Result<>(Result.CODE_FAILED, msg, data));
            }
            //创建之后才有id
            GenericClass savedData = (GenericClass)this.getEntityRepository().save(data);
            this.doAfterCreated(data, savedData);
            result = new Result<>(Result.CODE_SUCCESS, "", savedData);
        } catch (Exception e) {
            LogOperator.err(loggerName, "create error", e);
            result = new Result<>(Result.CODE_FAILED, e.getMessage(), data);
        }
        LogOperator.debug(loggerName, "create result = "+result);
        return transColumnName(result);
    }

    @Override
    public  Result<GenericClass> modify(GenericClass data) {
        LogOperator.debug(loggerName, "modify data = "+data);
        Result<GenericClass> result = null;
        try {
            String msg = beforeModify(data);
            if((!StringUtils.isEmpty(msg))){
                return transColumnName(new Result<>(Result.CODE_FAILED, msg, data));
            }
            GenericClass savedData =  (GenericClass)this.getEntityRepository().save(data);
            this.doAfterModified(data, savedData);
            result = new Result<>(Result.CODE_SUCCESS, "", savedData);
        } catch (Exception e) {
            LogOperator.err(loggerName, "modify error", e);
            result = new Result<>(Result.CODE_FAILED, e.getMessage(), data);
        }
        LogOperator.debug(loggerName, "modify result = "+result);
        return transColumnName(result);
    }

    @Override
    public Result<GenericClass> modify(Class clazz, Long id, Map<String, Object> partFieldValueMap) {
        LogOperator.debug(loggerName, "modify data: clazz = " + clazz + ",id = " + id + ",partFieldValueMap = " + partFieldValueMap);

        GenericClass data = this.findById(id);
        if (data == null) {
            return transColumnName(new Result<>(Result.CODE_FAILED, "要修改的" + getEntityDisplayName( getGenericClassType(0)) + "不存在"));
        }

        List<Field> fieldList = getClassFields(clazz);
        for (String key : partFieldValueMap.keySet()) {
            for (Field field:fieldList) {
                if (field.getName().equals(key)) {
                    try {
                        Reflections.setFieldValue(data, key, convertValue2Object(field.getType(), partFieldValueMap.get(key)));
                    } catch (Exception e){
                        LogOperator.err(loggerName, "setFieldValue error", e);
                    }
                    break;
                }
            }
        }
        return this.modify(data);
    }

    @Override
    public Result<GenericClass>  delete(GenericClass data){
        LogOperator.debug(loggerName, "delete data = "+data);
        Result<GenericClass> result = null;
        try {
            if (data == null) {
                throw new Exception("参数为空");
            }
            Long deleteId = getIdFromEntity(data);
            if(deleteId == null){
                throw new Exception("参数ID为空");
            }
            GenericClass dt = findById(deleteId) ;
            if (dt == null){
                throw new Exception("删除的"+getEntityDisplayName( getGenericClassType(0))+"不存在:" + data);
            }
            this.doBeforeDeleted(dt);
            this.getEntityRepository().delete(dt);
            result = new Result<>(Result.CODE_SUCCESS, "", data);
        } catch (Exception e) {
            LogOperator.err(loggerName, "delete error", e);
            result = new Result<>(Result.CODE_FAILED, e.getMessage(), data);
        }
        LogOperator.debug(loggerName, "modify result = "+result);
        return transColumnName(result);
    }

    @Override
    public void  delete(Long id){
        LogOperator.debug(loggerName, "delete id = "+id);
        Result<GenericClass> result = null;
        try {
            GenericClass data = findById(id) ;
            if (data == null){
                throw new Exception("删除的"+getEntityDisplayName( getGenericClassType(0))+"不存在:" + data);
            }
            this.doBeforeDeleted(data);
            getEntityRepository().delete(id);
        } catch (Exception e) {
            LogOperator.err(loggerName, "delete error", e);
        }
        LogOperator.debug(loggerName, "delete ok");
    }

    @Override
    public List<GenericClass> findAll() {
        List<GenericClass> result = null;
        try {
            result = getEntityRepository().findAll();
        } catch (Exception e) {
            LogOperator.err(loggerName, "findAll error", e);
            result = Collections.EMPTY_LIST;
        }
        LogOperator.debug(loggerName, "findAll result = "+result);
        return result;
    }

    @Override
    public GenericClass findById(Long id) {
        LogOperator.debug(loggerName, "findById id = "+id);
        GenericClass result = (GenericClass) getEntityRepository().findOne(id);
        LogOperator.debug(loggerName, "findById result = "+result);
        return result;
    }

    @Override
    public List<GenericClass> findByQueryCondition(Map<String, Object> queryCondMap) {
        List<GenericClass> result = findByQueryCondition( queryCondMap ,null);
        return result;
    }

    @Override
    public List<GenericClass> findByQueryCondition(List<SimpleExpression> queryCondSimple) {
        List<GenericClass> result =  findByQueryCondition( null ,queryCondSimple);
        return result;
    }
    @Override
    public List<GenericClass> findByQueryCondition(SimpleExpression simpleExpression) {
        List<SimpleExpression> queryCondSimple = new ArrayList<SimpleExpression>();
        queryCondSimple.add(simpleExpression);
        List<GenericClass> result =  findByQueryCondition( null ,queryCondSimple);
        return result;
    }
    @Override
    public Page<GenericClass>  findByQueryCondition(int page, int size, String order, String orderBy, Map<String, Object> queryCondMap) {
        Sort.Direction der = Sort.Direction.ASC.name().equalsIgnoreCase(order) ? Sort.Direction.ASC : Sort.Direction.DESC;
        PageRequest pageable = new PageRequest(page - 1, size, new Sort(der, orderBy));
        return findByQueryCondition( queryCondMap ,null, pageable);
    }

    @Override
    public Page<GenericClass> findByQueryCondition(int page, int size, String order, String orderBy, List<SimpleExpression> queryCondSimple) {
        Sort.Direction der = Sort.Direction.ASC.name().equalsIgnoreCase(order) ? Sort.Direction.ASC : Sort.Direction.DESC;
        PageRequest pageable = new PageRequest(page - 1, size, new Sort(der, orderBy));
        return findByQueryCondition( null, queryCondSimple, pageable);
    }

    @Override
    public TableJsonData findByTableQueryCondition(TableDataQueryCondition tableDataQueryCondition) {
        PageRequest pageable = TableDataQueryCondition.getPageRequestByTableDataQueryCondition(tableDataQueryCondition);
        //一、处理原有Map查询条件,将其放入简单条件列表中统一处理
        Map queryCondMap = tableDataQueryCondition.getQueryCond();
        List<SimpleExpression> queryCondSimple = tableDataQueryCondition.getQueryCondSimple();
        Page<GenericClass> ret = findByQueryCondition( queryCondMap ,queryCondSimple, pageable);

        return new TableJsonData(tableDataQueryCondition, ret.getTotalElements(), ret.getContent());
    }

    @Override
    public String export(HttpServletRequest request, HttpServletResponse response){
        try {
            String date = DateFormatUtils.format(new Date(), "yyyyMMddHHmmss");
            String fileName = getGenericClassType(0).getSimpleName() + "_" + date + ".xlsx";
            List<GenericClass> entityList;
            Map<String, String[]> parameterMap = request.getParameterMap();
            if (parameterMap.isEmpty()) {
                entityList = getEntityRepository().findAll();
            } else {
                Map<String, Object> condMap = new HashMap<>();
                for (String key:parameterMap.keySet()) {
                    condMap.put(key, request.getParameter(key));
                }
                entityList = this.findByQueryCondition(condMap);
            }
            ExportExcel exportExcel =new ExportExcel(getEntityDisplayName(getGenericClassType(0)), getGenericClassType(0));
            exportExcel.setDatePattern("yyyy-MM-dd HH:mm:ss");
            exportExcel .setDataList(entityList).write(response, fileName).dispose();
        } catch (IOException e) {
            LogOperator.err(loggerName, "export info failed!", e);
        }
        return null;
    }

    protected GenericClass doAfterCreated(GenericClass data, GenericClass returnedData) {
        return data;
    }

    protected GenericClass doAfterModified(GenericClass data, GenericClass returnedData) {
        return data;
    }

    protected GenericClass doBeforeDeleted(GenericClass data) throws Exception {
        return data;
    }

    private List<GenericClass>  findByQueryCondition( Map queryCondMap ,List<SimpleExpression> queryCondSimple) {
        LogOperator.debug(loggerName, "findByQueryCondition queryCondMap = "+queryCondMap+",queryCondSimple = "+queryCondSimple);
        Criteria<GenericClass> criteria = new Criteria<>();
        processCriteria(criteria, queryCondMap ,queryCondSimple);
        List<GenericClass>  result = this.getEntityRepository().findAll(criteria);
        LogOperator.debug(loggerName, "findByQueryCondition result = "+result);
        return result;
    }

    private Long countByQueryCondition(Map queryCondMap ,List<SimpleExpression> queryCondSimple) {
        if (LogOperator.isDebugEnabled(loggerName)) {
            LogOperator.debug(loggerName, "countByQueryCondition queryCondMap = " + queryCondMap + ", queryCondSimple = " + queryCondSimple);
        }
        Criteria<GenericClass> criteria = new Criteria<>();
        processCriteria(criteria, queryCondMap ,queryCondSimple);
        Long  result = this.getEntityRepository().count(criteria);
        if (LogOperator.isDebugEnabled(loggerName)) {
            LogOperator.debug(loggerName, "countByQueryCondition result = " + result);
        }
        return result;
    }

    public Page<GenericClass> findByQueryCondition( Map queryCondMap ,List<SimpleExpression> queryCondSimple, Pageable pageable) {
        LogOperator.debug(loggerName, "findByQueryCondition queryCondMap = "+queryCondMap+",queryCondSimple = "+queryCondSimple+",pageable = "+pageable);
        Criteria<GenericClass> criteria = new Criteria<>();
        processCriteria(criteria, queryCondMap ,queryCondSimple);
        Page<GenericClass> result = this.getEntityRepository().findAll(criteria,pageable);
        LogOperator.debug(loggerName, "findByQueryCondition result = "+result);
        return result;
    }

    private String getEntityDisplayName(Class clazz){
        try {
            Field field = clazz.getField("ENTITY_DISPLAY_NAME");
            if(field != null) {
                return (String) field.get(clazz);
            }
        } catch (Exception e) {
            LogOperator.err(loggerName, "getEntityDisplayName failed!", e);
        }
        return clazz.getSimpleName();
    }


    //泛型类作为父类，可以获取子类的所有实际参数的类型
    @SuppressWarnings("unchecked")
    private Class<GenericClass> getGenericClassType(int index){
        Type[] params = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();//一个泛型类可能有多个泛型形参，比如ClassName<T,K> 这里有两个泛型形参T和K，Class Name<T> 这里只有1个泛型形参T
        Class<GenericClass> modelClass = (params.length-1<index) ? null :(Class) params[index] ;

        return modelClass;
    }

    protected  String beforeModify(GenericClass data) {
        String msg = checkParaNull(data);
        if(!StringUtils.isEmpty(msg)) {
            return msg;
        }
        GenericClass curByIdInDb = findById(getIdFromEntity(data));
        if (curByIdInDb == null) {
            msg = "修改的"+getEntityDisplayName( getGenericClassType(0))+"不存在";
            LogOperator.info(loggerName, msg + ":" + data);
            return msg;
        }

        Long id = this.getIdFromEntity(data);
        msg = this.persistedObjectFieldDuplicated(data, id);
        if(!StringUtils.isEmpty(msg)){
            return msg;
        }

        msg = this.persistedObjectUniqueConstraint(data, id);
        if(!StringUtils.isEmpty(msg)){
            return msg;
        }

        if (data instanceof BaseEntity) {
            BaseEntity baseEntity = (BaseEntity)data;
            baseEntity.setGmtCreate(((BaseEntity)curByIdInDb).getGmtCreate());
            baseEntity.setGmtModified(new Date());
        }

        return msg;
    }

    protected  String beforeCreate(GenericClass data) {
        String msg = checkParaNull(data);
        if(!StringUtils.isEmpty(msg)){
            return msg;
        }

        Long id = this.getIdFromEntity(data);
        if ( id != null && id > 0){
            LogOperator.info(loggerName, "id已赋值");
        }
        id = 0L;
        setId(data, id);

        msg = this.persistedObjectFieldDuplicated(data, id);
        if(!StringUtils.isEmpty(msg)){
            return msg;
        }

        msg = this.persistedObjectUniqueConstraint(data, id);
        if(!StringUtils.isEmpty(msg)){
            return msg;
        }

        if (data instanceof BaseEntity) {
            BaseEntity baseEntity = (BaseEntity)data;
            baseEntity.setGmtCreate(new Date());
            baseEntity.setGmtModified(null);
        }

        return msg;
    }

    /**
     * 对非空属性的合法性检查
     * @param data 实体类对象
     * @return 存在输入非法时返回提示信息，正常情况下返回null
     */
    protected String checkParaNull(GenericClass data){
        String entityDisName = getEntityDisplayName( getGenericClassType(0));
        if (data == null) {
            return entityDisName + "参数为空，请补充！";
        }
        String msg = persistedObjectContainsNull(data);
        if (!StringUtils.isEmpty(msg) ) {
            return entityDisName + "输入信息不全，如下属性为空：" + msg;
        }

        return null;
    }

    private static void addFields(Class<?> clazz, List<Field> result) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field f : fields) {
            result.add(f);
        }
    }

    protected static List<Field> getClassFields(Class clazz){
        List<Field> propertyFields = new ArrayList<>();
        // 向列表增加所有父类的Field
        Class<?> superClazz = clazz.getSuperclass();
        while (!superClazz.getName().equals("java.lang.Object")) {
            addFields(superClazz, propertyFields);
            superClazz = superClazz.getSuperclass();
        }
        addFields(clazz, propertyFields);
        return propertyFields;
    }


    private void setId(GenericClass data, long value) {
        if (data instanceof BaseEntity) {
            ((BaseEntity)data).setId(value);
        } else {
            try {
                Reflections.setFieldValue(data,"id", value);
            } catch (Exception e){
                LogOperator.err(loggerName, "setId error", e);
            }
        }
    }

    private Long getIdFromEntity(GenericClass data) {
        Long id = 0L;
        if (data instanceof BaseEntity) {
            id = ((BaseEntity)data).getId();
        } else {
            try {
                id = (Long) Reflections.getFieldValue(data,"id");
            } catch (Exception e){
                LogOperator.err(loggerName, "getIdFromEntity error", e);
            }
        }
        return id;
    }

    private Criteria<GenericClass> processCriteria(Criteria<GenericClass> criteria, Map queryCondMap , List<SimpleExpression> queryCondSimple) {
        if(queryCondMap != null && queryCondMap.size() > 0){
            Set<String> fieldNames =  queryCondMap.keySet();
            for(String fieldName:fieldNames){
                Object valObject = queryCondMap.get(fieldName);
                if (valObject == null) {
                    continue;
                }
                Field field = getField(fieldName);
                if(field != null){
                    if((Number.class.isAssignableFrom(field.getType()) || Date.class.isAssignableFrom(field.getType())) && (valObject instanceof String)) {
                        String fVal = ((String) valObject).trim();
                        if (fVal.contains(Criterion.SEPARATOR_SEMICOLON)) {
                            String[] minMaxConds = fVal.split(Criterion.SEPARATOR_SEMICOLON);
                            if (minMaxConds.length == 1) {
                                Object oValue = convertValue2Object(field.getType(), minMaxConds[0]);
                                if (!fVal.contains(Criterion.SEPARATOR_SEMICOLON)) {
                                    criteria.add(Restrictions.eq(fieldName, oValue));
                                } else if (fVal.startsWith(Criterion.SEPARATOR_SEMICOLON)) {
                                    if (oValue instanceof Date) {
                                        criteria.add(Restrictions.lt(fieldName, DateUtil.getNextDay((Date) oValue)));
                                    } else {
                                        criteria.add(Restrictions.lte(fieldName, oValue));
                                    }
                                } else if (fVal.endsWith(Criterion.SEPARATOR_SEMICOLON)) {
                                    criteria.add(Restrictions.gte(fieldName, oValue));
                                }
                            } else if (minMaxConds.length > 1) {
                                minMaxConds[0] = (StringUtils.isEmpty(minMaxConds[0]) ? null : minMaxConds[0].trim());
                                minMaxConds[1] = (StringUtils.isEmpty(minMaxConds[1]) ? null : minMaxConds[1].trim());
                                Object minValue = convertValue2Object(field.getType(), minMaxConds[0]);
                                Object maxValue = convertValue2Object(field.getType(), minMaxConds[1]);
                                if (minValue != null) {
                                    criteria.add(Restrictions.gte(fieldName, minValue));
                                }
                                if (maxValue != null) {
                                    if (maxValue instanceof Date) {
                                        criteria.add(Restrictions.lt(fieldName, DateUtil.getNextDay((Date) maxValue)));
                                    } else {
                                        criteria.add(Restrictions.lte(fieldName, maxValue));
                                    }
                                }
                            }
                        } else if (fVal.startsWith("[") && fVal.endsWith("]")) {
                            if (fVal.length() > 2) {
                                String[] arr = fVal.substring(1, fVal.length() - 2).split(",");
                                List<String> list = new ArrayList<>();
                                for (int i = 0, size = arr.length; i < size; i++) {
                                    if (!StringUtils.isEmpty(arr[i])) {
                                        list.add(arr[i]);
                                    }
                                }
                                if (list.size() > 0) {
                                    criteria.add(Restrictions.in(fieldName, list));
                                }
                            }
                        } else {
                            criteria.add(Restrictions.eq(fieldName,valObject));
                        }
                    } else if(String.class.isAssignableFrom(field.getType()) && (valObject instanceof String)){
                        String strVal = ((String) valObject).trim();
                        if (!StringUtils.isEmpty(strVal) && !strVal.equals("%") && !strVal.equals("%%")) {
                            if (strVal.startsWith("%")) {
                                if (strVal.endsWith("%") && strVal.length()>2) {
                                    criteria.add(Restrictions.like(fieldName, strVal.substring(1,strVal.length()-1), Criterion.MatchMode.ANYWHERE));
                                } else {
                                    criteria.add(Restrictions.like(fieldName, strVal.substring(1), Criterion.MatchMode.START));
                                }
                            } else if (strVal.endsWith("%")) {
                                criteria.add(Restrictions.like(fieldName, strVal.substring(0, strVal.length()-1), Criterion.MatchMode.END));
                            } else if (strVal.startsWith("[") && strVal.endsWith("]")) {
                                if (strVal.length() > 2) {
                                    String[] arr = strVal.substring(1, strVal.length() - 2).split(",");
                                    List<String> list = new ArrayList<>();
                                    for (int i = 0, size = arr.length; i < size; i++) {
                                        if (!StringUtils.isEmpty(arr[i])) {
                                            list.add(arr[i]);
                                        }
                                    }
                                    if (!list.isEmpty()) {
                                        criteria.add(Restrictions.in(fieldName, list));
                                    }
                                }
                            } else {
                                criteria.add(Restrictions.eq(fieldName, strVal));
                            }
                        }
                    } else {
                        criteria.add(Restrictions.eq(fieldName,valObject));
                    }
                }
            }
        }
        //二、处理简单条件列表
        if (queryCondSimple != null && queryCondSimple.size() > 0){
            for(SimpleExpression se:queryCondSimple){
                Field field = getField(se.getFieldName());
                if(field != null){
                    se.setValue(convertValue2Object(field.getType(),se.getValue()));
                    se.setMinValue(convertValue2Object(field.getType(),se.getMinValue()));
                    se.setMaxValue(convertValue2Object(field.getType(),se.getMaxValue()));
                    List valueList = se.getValueList();
                    if (valueList != null &&  valueList.size() >0){
                        List newValueList = new ArrayList( valueList.size());
                        Object tmpValue;
                        for (int i = 0; i < valueList.size(); i++){
                            tmpValue = convertValue2Object(field.getType(),valueList.get(i));
                            if (tmpValue != null){
                                newValueList.add(tmpValue);
                            }
                        }
                        se.setValueList(newValueList);
                    }
                    criteria.add(se);
                }
            }
        }
        return criteria;
    }

    /**
     * values : [1,2,3]
     * @param values
     * @return
     */
    private List processCriteriaInCondition(String values){
        if(StringUtils.isEmpty(values) || values.length() == 2){
            return Collections.EMPTY_LIST;
        }
        String[] arr = values.substring(1, values.length()-1).split(",");
        List<String> list = new ArrayList<>();
        for (int i = 0, size=arr.length; i < size; i++) {
            if (!StringUtils.isEmpty(arr[i])) {
                list.add(arr[i]);
            }
        }
        return list;
    }
    private Field getField(String fieldName){
        Field field = null;
        try {
            field = getGenericClassType(0).getDeclaredField(fieldName);
        }catch (Exception e){
            LogOperator.err(loggerName, "getField error", e);
        }
        return field;
    }

    protected Object convertValue2Object(Class clazz,Object value){
        if (value == null || clazz == null){
            return null;
        }
        Object newValue = value;
        try {
            if(Number.class.isAssignableFrom(clazz) && !(value instanceof Number)
                || Integer.class.isAssignableFrom(clazz) && !(value instanceof Integer)
                    || Double.class.isAssignableFrom(clazz) && !(value instanceof Double)
                    || Float.class.isAssignableFrom(clazz) && !(value instanceof Float)){
                Method method = clazz.getMethod("valueOf", String.class);
                newValue = method.invoke(null, value.toString());
            }else if(Date.class.isAssignableFrom(clazz ) && !(value instanceof Date)){
                newValue = DateUtil.parseDate(value);
            }
        } catch (Exception e) {
            LogOperator.err(loggerName, "convertValue2Object error", e);
        }
        return newValue;
    }

    /**
     * 对非空属性的合法性检查
     * @param obj 实体类对象
     * @return 存在输入非法时返回提示信息，正常情况下返回null
     */
    protected String persistedObjectContainsNull(Object obj) {
        if(obj == null){
            return "对象为空";
        }
        StringBuilder sb = new StringBuilder();
        // 对象属性的Field
        checkObjectContainsNull(sb ,obj);
        if(sb.length() > 0){
            sb.deleteCharAt(sb.length()-1);
        }
        return sb.toString();
    }

    private void checkObjectContainsNull(StringBuilder sb ,Object obj){
        Class objClass = obj.getClass();
        Entity classEntityMeta = (Entity) objClass.getAnnotation(Entity.class);
        Embeddable classEmbeddableMeta = (Embeddable) objClass.getAnnotation(Embeddable.class);
        Embedded classEmbeddedMeta = (Embedded) objClass.getAnnotation(Embedded.class);
        //不是持久化实体
        if(classEntityMeta == null && classEmbeddableMeta == null && classEmbeddedMeta == null) {
            return ;
        }
        List<Field> propertyFields = getClassFields(objClass);
        for (Field field : propertyFields) {
            field.setAccessible(true);
            Column fieldColumnMeta = field.getAnnotation(Column.class);
            //20180118,新增使用场景:实体嵌入实体的情况,需要递归判断
            if (fieldColumnMeta == null) {
                Embedded fieldEmbeddedMeta = field.getAnnotation(Embedded.class);
                if(fieldEmbeddedMeta == null){
                    continue;
                }else{
                    checkObjectContainsNull(sb ,Reflections.getFieldValue(obj, field.getName()));
                }
            }else{
                 if(fieldColumnMeta.nullable()){
                     continue;
                 }
            }
            ExcelField fieldExcelFieldMeta = field.getAnnotation(ExcelField.class);
            String fieldDispName = fieldExcelFieldMeta == null ? field.getName() : fieldExcelFieldMeta.title();
            Object fieldValue = Reflections.getFieldValue(obj, field.getName());
            if (fieldValue == null) {
                sb.append(fieldDispName).append(";");
            }
        }
    }
    private boolean isBaseJavaType(Field field){
        Type type = field.getType();
        boolean isBaseJavaType = false;
        if (type == int.class
                || type == Integer.class
                || type == long.class
                || type == Long.class
                || type == double.class
                || type == Double.class
                || type == byte.class
                || type == Byte.class
                || type == boolean.class
                || type == Boolean.class
                || type == float.class
                || type == Float.class
                || type == short.class
                || type == Short.class
                || type == String.class
                ) {
            isBaseJavaType = true;
        }
        return isBaseJavaType;
    }
    /**
     * 对联合唯一性约束UniqueConstraint的合法性检查
     * @param obj 实体类对象
     * @return 存在输入非法时返回提示信息，正常情况下返回null
     */
    protected String persistedObjectUniqueConstraint(Object obj, Long id) {
        Class objClass = obj.getClass();
        Table classEntityMeta = (Table) objClass.getAnnotation(Table.class);
        if(classEntityMeta == null) {
            return null;
        }
        for (UniqueConstraint uniqueConstraint:classEntityMeta.uniqueConstraints()) {
            String[] columnNames = uniqueConstraint.columnNames();
            StringBuilder sb = new StringBuilder("已存在以下信息相同的记录：");
            Map<String, Object> queryCondMap = new HashMap<>();
            for (String fieldName:columnNames) {
                Object fieldValue = Reflections.getFieldValue(obj, fieldName);
                sb.append(this.getFieldDisplayName((GenericClass) obj, fieldName)).append("+");
                queryCondMap.put(fieldName, fieldValue);
            }
            List<GenericClass> list = findByQueryCondition(queryCondMap);
            if (!list.isEmpty() && !id.equals(getIdFromEntity(list.get(0)))) {
                return sb.deleteCharAt(sb.length()-1).toString();
            }
        }

        return null;
    }

    /**
     * 对违反单属性唯一性约束Unique的合法性检查
     * @param obj 实体类对象
     * @param id 源实体类对象的主键值
     * @return 存在输入非法时返回提示信息，正常情况下返回null
     */
    protected String persistedObjectFieldDuplicated(Object obj, Long id) {
        Class objClass = obj.getClass();
        // 对象属性的Field
        List<Field> propertyFields = getClassFields(objClass);
        for (Field field : propertyFields) {
            try {
                field.setAccessible(true);
                Column fieldColumnMeta = field.getAnnotation(Column.class);
                if (fieldColumnMeta == null) {
                    continue;
                }

                int allowLength = fieldColumnMeta.length();
                String fieldName = field.getName();
                Object fieldValue = Reflections.getFieldValue(obj, fieldName);
                ExcelField fieldExcelFieldMeta = field.getAnnotation(ExcelField.class);
                String fieldDisplayName = fieldExcelFieldMeta == null ? fieldName : fieldExcelFieldMeta.title();

                if (String.class.isAssignableFrom(field.getType()) && fieldValue != null && fieldValue.toString().length() > allowLength) {
                    return fieldDisplayName + "太长！最大长度为" + allowLength;
                }

                if (!fieldColumnMeta.unique()) {
                    continue;
                }
                //当前字段要求唯一
                Map<String, Object> queryCondMap = new HashMap<>();
                queryCondMap.put(fieldName, fieldValue);
                List<GenericClass> list = findByQueryCondition(queryCondMap);
                System.out.println("fieldName = "+ fieldName + ",fieldValue = "+fieldValue+", find list = " + list);
                Long curId = 0L;
                for (GenericClass e : list) {
                    //获取数据库中数据的ID
                    curId = getIdFromEntity(e);
                    Object efv = Reflections.getFieldValue(e, fieldName);
                    if (curId != null && curId != 0
                            && curId != id) {
                        if( (fieldValue == null && efv == null)
                                ||  (fieldValue != null && efv != null && fieldValue.equals(efv))){
                            return fieldDisplayName + "不能重复！值为"+fieldValue;
                        }
                    }
                }
            }catch(Exception e){
                    LogOperator.err(loggerName, "persistedObjectFieldDuplicated error", e);
            }
        }

        return null;
    }

    public String getFieldDisplayName(GenericClass entityT,String fieldName){
        if(entityT == null){
            return fieldName;
        }
        Field field = Reflections.getAccessibleField(entityT,fieldName);
        if(field != null){
            ExcelField fieldExcelFieldMeta = field.getAnnotation(ExcelField.class);
            return fieldExcelFieldMeta == null ? fieldName: fieldExcelFieldMeta.title();
        }
        return fieldName;
    }

    /**
     * 导入文件内容
     * @param file
     * @param request
     * @return
     */
    @Override
    public Result<Integer> fileImport(MultipartFile file, HttpServletRequest request){
        return null;
    }


    @Override
    public Result<GenericClass> transColumnName(Result<GenericClass> result) {
        return result;
    }
}
